package com.ipan.builder;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;

import com.ipan.builder.BuilderCfg.BuildCfg;
import com.ipan.builder.db.DatabaseOp;
import com.ipan.builder.db.DefaultDataBaseOp;
import com.ipan.builder.entity.DefaultEntityOp;
import com.ipan.builder.entity.EntityOp;
import com.ipan.builder.entity.JpaEntityCfg;
import com.ipan.builder.ext.entity.DefEntityCfg;
import com.ipan.builder.freemarker.FreemarkerManager;
import com.ipan.builder.ognl.OgnlValueStackManager;
import com.ipan.builder.ognl.ValueStack;
import com.ipan.builder.var.CommonVariateOp;
import com.ipan.builder.var.ExtendVariateOp;
import com.ipan.builder.var.VariateOp;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * 代码生成器
 * 
 * <pre>
 * 2015-01-24	追加了对自定义实体的代码生成；
 * </pre>
 * @author iPan
 * @version 2013-11-27
 */
public class Builder implements EntityOp {
	private ValueStack vs;
	private VariateOp commVarOp;
	private VariateOp extVarOp;
	private EntityOp entityOp;
	private DatabaseOp dbOp;
	private static Builder INSTANCE = new Builder();

	private Builder() {
		this.vs = OgnlValueStackManager.createOgnlValueStack();
		this.dbOp = new DefaultDataBaseOp();
		this.entityOp = new DefaultEntityOp(vs);
		this.commVarOp = new CommonVariateOp(vs);
		this.extVarOp = new ExtendVariateOp(vs);
		// 初始化公共变量
		this.commVarOp.putAll(BuilderCfg.getInstance().getCommonVarMap());
		// 将BuilderCfg放入VS
		vs.push(BuilderCfg.getInstance());
	}
	
	public static Builder createBuilder() {
		return INSTANCE;
	}
	
	public EntityOp getEntityOp() {
		return entityOp;
	}

	public void setEntityOp(EntityOp entityOp) {
		this.entityOp = entityOp;
	}

	public DatabaseOp getDbOp() {
		return dbOp;
	}

	public void setDbOp(DatabaseOp dbOp) {
		this.dbOp = dbOp;
	}

	public ValueStack getVs() {
		return vs;
	}

	public void setVs(ValueStack vs) {
		this.vs = vs;
	}

	public VariateOp getCommVarOp() {
		return commVarOp;
	}

	public void setCommVarOp(VariateOp commVarOp) {
		this.commVarOp = commVarOp;
	}

	public VariateOp getExtVarOp() {
		return extVarOp;
	}

	public void setExtVarOp(VariateOp extVarOp) {
		this.extVarOp = extVarOp;
	}

	public String buildTemplateName(String fileName) {
		return buildTemplateName(vs, fileName);
	}

	public String getFtlExprValue(String group) {
		return getFtlExprValue(vs, group);
	}
	
	public static String buildTemplateName(ValueStack vs, String fileName) {
		if (fileName.indexOf("${") < 0) {
			return fileName;
		}
		String name = fileName;
		for (int p1 = name.indexOf("${"); p1 >= 0; p1 = name.indexOf("${")) {
			int p2 = name.indexOf("}");
			String expr = name.substring(p1, p2 + 1);
			String value = getFtlExprValue(vs, expr);
			name = name.replaceFirst("\\$\\{[\\w\\s]+\\}", value);
		}
		return name;
	}

	// ${name} -> value
	// ${ name } -> value
	public static String getFtlExprValue(ValueStack vs, String group) {
		String expr = group.substring(2, group.length() - 1).trim();
		return (String) vs.findValue(expr);
	}

	/**
	 * JpaEntityCfg + All BuildCfg
	 */
	public void buildCode(JpaEntityCfg entityCfg) {
		entityOp.buildCode(entityCfg);
	}

	/**
	 * JpaEntityCfg + BuildCfg
	 */
	public void buildCode(JpaEntityCfg entityCfg, BuildCfg buildCfg) {
		entityOp.buildCode(entityCfg, buildCfg);
	}

	/**
	 * All JpaEntityCfg + All BuildCfg
	 */
	public void buildAllEntites() {
		entityOp.buildAllEntites();
	}

	/**
	 * All JpaEntityCfg + BuildCfg
	 */
	public void buildAllEntites(BuildCfg buildCfg) {
		entityOp.buildAllEntites(buildCfg);
	}
	
	/**
	 * 放入所有公共变量
	 */
	public void putAllCommVar(Map<String, Object> vals) {
		this.commVarOp.putAll(vals);
	}
	
	/**
	 * 放入公共变量
	 */
	public void putCommVar(String key, Object value) {
		this.commVarOp.putVar(key, value);
	}
	
	/**
	 * 获取公共变量
	 */
	public Object getCommVar(String key) {
		return this.commVarOp.getVar(key);
	}
	
	/**
	 * 移除公共变量
	 */
	public void removeCommVar(String key) {
		this.commVarOp.removeVar(key);
	}
	
	/**
	 * 放入所有扩展变量
	 */
	public void putAllExtVar(Map<String, Object> vals) {
		this.extVarOp.putAll(vals);
	}
	
	/**
	 * 放入扩展变量
	 */
	public void putExtVar(String key, Object value) {
		this.extVarOp.putVar(key, value);
	}
	
	/**
	 * 获取扩展变量
	 */
	public Object getExtVar(String key) {
		return this.extVarOp.getVar(key);
	}
	
	/**
	 * 移除扩展变量
	 */
	public void removeExtVar(String key) {
		this.extVarOp.removeVar(key);
	}
	
	/**
	 * 生成指定模板，对实体类以外的代码生成的支持；
	 */
	public synchronized void buildTemplate(BuildCfg buildCfg) {
		String[] files = buildCfg.getFiles();
		if (files == null || files.length < 1) {
			return ;
		}
		
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		vs.push(buildCfg);
		for (String fileName : files) {
			Template template = null;
			try {
				String relativePath = buildCfg.getRelativeTemplatePath(fileName);
				template = config.getTemplate(relativePath);
			} catch (IOException e2) {
				continue ;
			}
			
			File file = null;
			Writer writer = null;
			try {
				file = buildCfg.createFile(Builder.buildTemplateName(vs, fileName));
				writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), FreemarkerManager.DEFAULT_ENCODING));
				template.process(FreemarkerManager.createOgnlHashModel(vs), writer);
			} catch(Exception e) {
				throw new RuntimeException("生成代码出错.", e);
			} finally {
				if (writer != null) {
					try {
						writer.close();
					} catch (IOException e1) {
					}
				}
			}
		}
		vs.pop();
	}

	@Override
	public void buildCode(DefEntityCfg entityCfg) {
		entityOp.buildCode(entityCfg);
	}

	@Override
	public void buildCode(DefEntityCfg entityCfg, BuildCfg buildCfg) {
		entityOp.buildCode(entityCfg, buildCfg);
	}

	@Override
	public void buildAllDefEntites() {
		entityOp.buildAllDefEntites();
	}

	@Override
	public void buildAllDefEntites(BuildCfg buildCfg) {
		entityOp.buildAllDefEntites(buildCfg);
	}
	
}
